package org.developer.websocket.controller;

import lombok.extern.slf4j.Slf4j;
import org.developer.websocket.handler.MessageHandler;
import org.developer.websocket.message.AuthRequest;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 说明
 *
 * <1> 处，解析 ws:// 地址上的 accessToken 的请求参。例如说：ws://127.0.0.1:8080?accessToken=芋艿 。
 * <2> 处，创建 AuthRequest 消息类型，并设置 accessToken 属性。
 * <3> 处，获得 AuthRequest 消息类型对应的 MessageHandler 消息处理器，然后调用 MessageHandler#execute(session, message) 方法，执行处理用户认证请求。
 */

@Controller
@ServerEndpoint("/")
@Slf4j
public class WebsocketServerEndpoint implements InitializingBean {

    /**
     * 消息类型与 MessageHandler 的映射
     */
    private static final Map<String, org.developer.websocket.handler.MessageHandler> HANDLERS = new HashMap<>();

    @Autowired
    private ApplicationContext applicationContext;



    @OnOpen
    public void opOpen(Session session, EndpointConfig config){

        log.info("[onOpen][session({}) 接入]",session);

        //<1>解析 accessToken
        List<String> accessTokenValues = session.getRequestParameterMap().get("accessToken");
        String accessToken = !CollectionUtils.isEmpty(accessTokenValues) ? accessTokenValues.get(0) : null;
        //<2>创建 AuthRequest 消息类型
        AuthRequest authRequest = new AuthRequest().setAccessToken(accessToken);
        //<3> 获取消息处理器
        MessageHandler messageHandler = HANDLERS.get(AuthRequest.TYPE);
        if(messageHandler == null){
            log.error("[onOpen][认证消息类型，不存在消息处理器]");
            return;
        }

        messageHandler.execute(session,authRequest);
    }

    @OnMessage
    public void onMessage(Session session,String message){
        log.info("[onMessage][session({}) 接收到一条消息({})]",session,message);
    }

    @OnClose
    public void onClose(Session session,CloseReason closeReason){
        log.info("[onClose][session({}) 连接关闭。关闭原因是({})}]", session, closeReason);
    }

    @OnError
    public void onError(Session session,Throwable throwable){
        log.error("[onClose][session({}) 发生异常]", session, throwable);
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        applicationContext.getBeansOfType(MessageHandler.class).values()
                .forEach(messageHandler -> HANDLERS.put(messageHandler.getType(),messageHandler));
        log.info("[afterPropertiesSet][消息处理器数量：{}]", HANDLERS.size());
    }
}
